
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" lang="zh_Hans">
  <head>
    <meta http-equiv="X-UA-Compatible" content="IE=Edge" />
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>在基于类的视图中使用混入 &#8212; Django 3.2.11.dev 文档</title>
    <link rel="stylesheet" href="../../_static/default.css" type="text/css" />
    <link rel="stylesheet" href="../../_static/pygments.css" type="text/css" />
    <script type="text/javascript" id="documentation_options" data-url_root="../../" src="../../_static/documentation_options.js"></script>
    <script type="text/javascript" src="../../_static/jquery.js"></script>
    <script type="text/javascript" src="../../_static/underscore.js"></script>
    <script type="text/javascript" src="../../_static/doctools.js"></script>
    <script type="text/javascript" src="../../_static/language_data.js"></script>
    <link rel="index" title="索引" href="../../genindex.html" />
    <link rel="search" title="搜索" href="../../search.html" />
    <link rel="next" title="迁移" href="../migrations.html" />
    <link rel="prev" title="使用基于类的视图处理表单" href="generic-editing.html" />



 
<script src="../../templatebuiltins.js"></script>
<script>
(function($) {
    if (!django_template_builtins) {
       // templatebuiltins.js missing, do nothing.
       return;
    }
    $(document).ready(function() {
        // Hyperlink Django template tags and filters
        var base = "../../ref/templates/builtins.html";
        if (base == "#") {
            // Special case for builtins.html itself
            base = "";
        }
        // Tags are keywords, class '.k'
        $("div.highlight\\-html\\+django span.k").each(function(i, elem) {
             var tagname = $(elem).text();
             if ($.inArray(tagname, django_template_builtins.ttags) != -1) {
                 var fragment = tagname.replace(/_/, '-');
                 $(elem).html("<a href='" + base + "#" + fragment + "'>" + tagname + "</a>");
             }
        });
        // Filters are functions, class '.nf'
        $("div.highlight\\-html\\+django span.nf").each(function(i, elem) {
             var filtername = $(elem).text();
             if ($.inArray(filtername, django_template_builtins.tfilters) != -1) {
                 var fragment = filtername.replace(/_/, '-');
                 $(elem).html("<a href='" + base + "#" + fragment + "'>" + filtername + "</a>");
             }
        });
    });
})(jQuery);</script>

  </head><body>

    <div class="document">
  <div id="custom-doc" class="yui-t6">
    <div id="hd">
      <h1><a href="../../index.html">Django 3.2.11.dev 文档</a></h1>
      <div id="global-nav">
        <a title="Home page" href="../../index.html">Home</a>  |
        <a title="Table of contents" href="../../contents.html">Table of contents</a>  |
        <a title="Global index" href="../../genindex.html">Index</a>  |
        <a title="Module index" href="../../py-modindex.html">Modules</a>
      </div>
      <div class="nav">
    &laquo; <a href="generic-editing.html" title="使用基于类的视图处理表单">previous</a>
     |
    <a href="../index.html" title="使用 Django" accesskey="U">up</a>
   |
    <a href="../migrations.html" title="迁移">next</a> &raquo;</div>
    </div>

    <div id="bd">
      <div id="yui-main">
        <div class="yui-b">
          <div class="yui-g" id="topics-class-based-views-mixins">
            
  <div class="section" id="s-using-mixins-with-class-based-views">
<span id="using-mixins-with-class-based-views"></span><h1>在基于类的视图中使用混入<a class="headerlink" href="#using-mixins-with-class-based-views" title="永久链接至标题">¶</a></h1>
<div class="admonition caution">
<p class="first admonition-title">警告</p>
<p class="last">这是一个进阶主题。在探索这些技术之前，建议先了解 <a class="reference internal" href="index.html"><span class="doc">Django 基于类的视图</span></a> 。</p>
</div>
<p>Django 内置的基于类的视图提供了很多功能，但你可能想单独使用有些功能。例如，你可能想写一个渲染一个模板来生成 HTTP 响应的视图，但你不能使用 <a class="reference internal" href="../../ref/class-based-views/base.html#django.views.generic.base.TemplateView" title="django.views.generic.base.TemplateView"><code class="xref py py-class docutils literal notranslate"><span class="pre">TemplateView</span></code></a> ；也许你只需要在 <code class="docutils literal notranslate"><span class="pre">POST</span></code> 时渲染一个模板，用 <code class="docutils literal notranslate"><span class="pre">GET</span></code> 来处理其他所有事。虽然你可以直接使用 <a class="reference internal" href="../../ref/template-response.html#django.template.response.TemplateResponse" title="django.template.response.TemplateResponse"><code class="xref py py-class docutils literal notranslate"><span class="pre">TemplateResponse</span></code></a>，但这很可能会导致重复代码。</p>
<p>因此 Django 也提供了很多混入，它们提供了更多的离散功能。比如模板渲染，被封装在 <a class="reference internal" href="../../ref/class-based-views/mixins-simple.html#django.views.generic.base.TemplateResponseMixin" title="django.views.generic.base.TemplateResponseMixin"><code class="xref py py-class docutils literal notranslate"><span class="pre">TemplateResponseMixin</span></code></a> 中。Django 参考文档中包含 <a class="reference internal" href="../../ref/class-based-views/mixins.html"><span class="doc">所有混入的完整文档</span></a>。</p>
<div class="section" id="s-context-and-template-responses">
<span id="context-and-template-responses"></span><h2>上下文和模板响应<a class="headerlink" href="#context-and-template-responses" title="永久链接至标题">¶</a></h2>
<p>提供了两个重要的混入，它们有助于在基于类的视图中使用模板时提供一个一致的接口。</p>
<dl class="docutils">
<dt><a class="reference internal" href="../../ref/class-based-views/mixins-simple.html#django.views.generic.base.TemplateResponseMixin" title="django.views.generic.base.TemplateResponseMixin"><code class="xref py py-class docutils literal notranslate"><span class="pre">TemplateResponseMixin</span></code></a></dt>
<dd><p class="first">每个返回 <a class="reference internal" href="../../ref/template-response.html#django.template.response.TemplateResponse" title="django.template.response.TemplateResponse"><code class="xref py py-class docutils literal notranslate"><span class="pre">TemplateResponse</span></code></a> 的内置视图都将调用 <code class="docutils literal notranslate"><span class="pre">TemplateResponseMixin</span></code> 提供的  <a class="reference internal" href="../../ref/class-based-views/mixins-simple.html#django.views.generic.base.TemplateResponseMixin.render_to_response" title="django.views.generic.base.TemplateResponseMixin.render_to_response"><code class="xref py py-meth docutils literal notranslate"><span class="pre">render_to_response()</span></code></a> 方法。大多数时候，这个方法会被你调用（例如，它被 <a class="reference internal" href="../../ref/class-based-views/base.html#django.views.generic.base.TemplateView" title="django.views.generic.base.TemplateView"><code class="xref py py-class docutils literal notranslate"><span class="pre">TemplateView</span></code></a> 和 <a class="reference internal" href="../../ref/class-based-views/generic-display.html#django.views.generic.detail.DetailView" title="django.views.generic.detail.DetailView"><code class="xref py py-class docutils literal notranslate"><span class="pre">DetailView</span></code></a> 共同实现的 <code class="docutils literal notranslate"><span class="pre">get()</span></code> 方法调用）；同样，你也不太可能需要覆盖它，但如果你想让你的响应返回一些没有通过 Django 模板渲染的东西，那么你会想要这样做。关于这个例子，请看 <a class="reference internal" href="#jsonresponsemixin-example"><span class="std std-ref">JSONResponseMixin 例子</span></a>。</p>
<p class="last"><code class="docutils literal notranslate"><span class="pre">render_to_response()</span></code> 本身会调用 <a class="reference internal" href="../../ref/class-based-views/mixins-simple.html#django.views.generic.base.TemplateResponseMixin.get_template_names" title="django.views.generic.base.TemplateResponseMixin.get_template_names"><code class="xref py py-meth docutils literal notranslate"><span class="pre">get_template_names()</span></code></a> ，默认情况下，它会在基于类的视图上查找 <a class="reference internal" href="../../ref/class-based-views/mixins-simple.html#django.views.generic.base.TemplateResponseMixin.template_name" title="django.views.generic.base.TemplateResponseMixin.template_name"><code class="xref py py-attr docutils literal notranslate"><span class="pre">template_name</span></code></a> ；另外两个混入（ <a class="reference internal" href="../../ref/class-based-views/mixins-single-object.html#django.views.generic.detail.SingleObjectTemplateResponseMixin" title="django.views.generic.detail.SingleObjectTemplateResponseMixin"><code class="xref py py-class docutils literal notranslate"><span class="pre">SingleObjectTemplateResponseMixin</span></code></a> 和 <a class="reference internal" href="../../ref/class-based-views/mixins-multiple-object.html#django.views.generic.list.MultipleObjectTemplateResponseMixin" title="django.views.generic.list.MultipleObjectTemplateResponseMixin"><code class="xref py py-class docutils literal notranslate"><span class="pre">MultipleObjectTemplateResponseMixin</span></code></a> ）覆盖了这一点，以在处理实际对象时提供更灵活的默认值。</p>
</dd>
<dt><a class="reference internal" href="../../ref/class-based-views/mixins-simple.html#django.views.generic.base.ContextMixin" title="django.views.generic.base.ContextMixin"><code class="xref py py-class docutils literal notranslate"><span class="pre">ContextMixin</span></code></a></dt>
<dd>每个需要上下文数据的内置视图，比如为了渲染一个模板（包括上面的 <code class="docutils literal notranslate"><span class="pre">TemplateResponseMixin</span></code> ），都应该将他们想确定传入的数据作为关键字参数传入 <a class="reference internal" href="../../ref/class-based-views/mixins-simple.html#django.views.generic.base.ContextMixin.get_context_data" title="django.views.generic.base.ContextMixin.get_context_data"><code class="xref py py-meth docutils literal notranslate"><span class="pre">get_context_data()</span></code></a> 调用。<code class="docutils literal notranslate"><span class="pre">get_context_data()</span></code> 返回一个字典；在 <code class="docutils literal notranslate"><span class="pre">ContextMixin</span></code> 中它返回它的关键字参数，但通常覆盖此项来增加更多成员到字典中。你也可以使用 <a class="reference internal" href="../../ref/class-based-views/mixins-simple.html#django.views.generic.base.ContextMixin.extra_context" title="django.views.generic.base.ContextMixin.extra_context"><code class="xref py py-attr docutils literal notranslate"><span class="pre">extra_context</span></code></a> 属性。</dd>
</dl>
</div>
<div class="section" id="s-building-up-django-s-generic-class-based-views">
<span id="building-up-django-s-generic-class-based-views"></span><h2>构造 Django 基于类的通用视图<a class="headerlink" href="#building-up-django-s-generic-class-based-views" title="永久链接至标题">¶</a></h2>
<p>让我们看看 Django 的两个基于类的通用视图是如何由提供离散功能的混入构建的。我们将考虑 <a class="reference internal" href="../../ref/class-based-views/generic-display.html#django.views.generic.detail.DetailView" title="django.views.generic.detail.DetailView"><code class="xref py py-class docutils literal notranslate"><span class="pre">DetailView</span></code></a> ，它渲染一个对象的 “详情” 视图，以及 <a class="reference internal" href="../../ref/class-based-views/generic-display.html#django.views.generic.list.ListView" title="django.views.generic.list.ListView"><code class="xref py py-class docutils literal notranslate"><span class="pre">ListView</span></code></a> ，它渲染一个对象列表，通常来自一个查询集，并可选择将它们分页。这里将介绍四个混入，无论是在处理单个 Django 对象还是多个对象时，它们都提供了有用的功能。</p>
<p>通用编辑视图（ <a class="reference internal" href="../../ref/class-based-views/generic-editing.html#django.views.generic.edit.FormView" title="django.views.generic.edit.FormView"><code class="xref py py-class docutils literal notranslate"><span class="pre">FormView</span></code></a>，和模型专用的视图 <a class="reference internal" href="../../ref/class-based-views/generic-editing.html#django.views.generic.edit.CreateView" title="django.views.generic.edit.CreateView"><code class="xref py py-class docutils literal notranslate"><span class="pre">CreateView</span></code></a>，<a class="reference internal" href="../../ref/class-based-views/generic-editing.html#django.views.generic.edit.UpdateView" title="django.views.generic.edit.UpdateView"><code class="xref py py-class docutils literal notranslate"><span class="pre">UpdateView</span></code></a> 和 <a class="reference internal" href="../../ref/class-based-views/generic-editing.html#django.views.generic.edit.DeleteView" title="django.views.generic.edit.DeleteView"><code class="xref py py-class docutils literal notranslate"><span class="pre">DeleteView</span></code></a> ），以及基于日期的通用视图中也涉及到混入。这些内容在 <a class="reference internal" href="../../ref/class-based-views/mixins.html"><span class="doc">混入参考文档</span></a> 中有所涉及。</p>
<div class="section" id="s-detailview-working-with-a-single-django-object">
<span id="detailview-working-with-a-single-django-object"></span><h3><code class="docutils literal notranslate"><span class="pre">DetailView</span></code> ：使用单个 Django 对象<a class="headerlink" href="#detailview-working-with-a-single-django-object" title="永久链接至标题">¶</a></h3>
<p>要显示一个对象的详情，我们基本上需要做两件事：我们需要查询对象，然后将该对象作为上下文，用一个合适的模板生成一个 <a class="reference internal" href="../../ref/template-response.html#django.template.response.TemplateResponse" title="django.template.response.TemplateResponse"><code class="xref py py-class docutils literal notranslate"><span class="pre">TemplateResponse</span></code></a> 。</p>
<p>为了得到对象，<a class="reference internal" href="../../ref/class-based-views/generic-display.html#django.views.generic.detail.DetailView" title="django.views.generic.detail.DetailView"><code class="xref py py-class docutils literal notranslate"><span class="pre">DetailView</span></code></a> 依赖于 <a class="reference internal" href="../../ref/class-based-views/mixins-single-object.html#django.views.generic.detail.SingleObjectMixin" title="django.views.generic.detail.SingleObjectMixin"><code class="xref py py-class docutils literal notranslate"><span class="pre">SingleObjectMixin</span></code></a> ，它提供一个 <a class="reference internal" href="../../ref/class-based-views/mixins-single-object.html#django.views.generic.detail.SingleObjectMixin.get_object" title="django.views.generic.detail.SingleObjectMixin.get_object"><code class="xref py py-meth docutils literal notranslate"><span class="pre">get_object()</span></code></a> 方法，该方法根据请求的 URL 来找出对象（它查找 URLconf 中声明的 <code class="docutils literal notranslate"><span class="pre">pk</span></code> 和 <code class="docutils literal notranslate"><span class="pre">slug</span></code> 关键字参数，并从视图上的 <a class="reference internal" href="../../ref/class-based-views/mixins-single-object.html#django.views.generic.detail.SingleObjectMixin.model" title="django.views.generic.detail.SingleObjectMixin.model"><code class="xref py py-attr docutils literal notranslate"><span class="pre">model</span></code></a>  属性查找对象，或者从提供的 <a class="reference internal" href="../../ref/class-based-views/mixins-single-object.html#django.views.generic.detail.SingleObjectMixin.queryset" title="django.views.generic.detail.SingleObjectMixin.queryset"><code class="xref py py-attr docutils literal notranslate"><span class="pre">queryset</span></code></a> 属性中查找）。<code class="docutils literal notranslate"><span class="pre">SingleObjectMixin</span></code> 还覆盖了 <a class="reference internal" href="../../ref/class-based-views/mixins-simple.html#django.views.generic.base.ContextMixin.get_context_data" title="django.views.generic.base.ContextMixin.get_context_data"><code class="xref py py-meth docutils literal notranslate"><span class="pre">get_context_data()</span></code></a> ，它被用于所有 Django 内置的基于类的视图，为模板渲染提供上下文数据。</p>
<p>然后为了生成一个 <a class="reference internal" href="../../ref/template-response.html#django.template.response.TemplateResponse" title="django.template.response.TemplateResponse"><code class="xref py py-class docutils literal notranslate"><span class="pre">TemplateResponse</span></code></a>， <a class="reference internal" href="../../ref/class-based-views/flattened-index.html#DetailView" title="DetailView"><code class="xref py py-class docutils literal notranslate"><span class="pre">DetailView</span></code></a> 使用了 <a class="reference internal" href="../../ref/class-based-views/mixins-single-object.html#django.views.generic.detail.SingleObjectTemplateResponseMixin" title="django.views.generic.detail.SingleObjectTemplateResponseMixin"><code class="xref py py-class docutils literal notranslate"><span class="pre">SingleObjectTemplateResponseMixin</span></code></a>，它扩展了 <code class="xref py py-class docutils literal notranslate"><span class="pre">TemplateResponseMixin</span></code>，如上所述的覆盖了 <a class="reference internal" href="../../ref/class-based-views/mixins-simple.html#django.views.generic.base.TemplateResponseMixin.get_template_names" title="django.views.generic.base.TemplateResponseMixin.get_template_names"><code class="xref py py-meth docutils literal notranslate"><span class="pre">get_template_names()</span></code></a>。它实际上提供了一组相当复杂的选项，但大多数人都会使用的主要选项是 <code class="docutils literal notranslate"><span class="pre">&lt;app_label&gt;/&lt;model_name&gt;</span> <span class="pre">_detail.html</span></code>。<code class="docutils literal notranslate"><span class="pre">_detail</span></code> 部分可以通过在子类上设置 <a class="reference internal" href="../../ref/class-based-views/mixins-single-object.html#django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_suffix" title="django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_suffix"><code class="xref py py-attr docutils literal notranslate"><span class="pre">template_name_suffix</span></code></a> 来改变。（例如 <a class="reference internal" href="generic-editing.html"><span class="doc">通用编辑视图</span></a> 的创建和更新视图使用 <code class="docutils literal notranslate"><span class="pre">_form</span></code>，删除视图使用 <code class="docutils literal notranslate"><span class="pre">_confirm_delete</span></code>。）</p>
</div>
<div class="section" id="s-listview-working-with-many-django-objects">
<span id="listview-working-with-many-django-objects"></span><h3><code class="docutils literal notranslate"><span class="pre">ListView</span></code> ：使用多个 Django 对象<a class="headerlink" href="#listview-working-with-many-django-objects" title="永久链接至标题">¶</a></h3>
<p>对象列表大致遵循相同的模式：我们需要一个（可能是分页的）对象列表，通常是 <a class="reference internal" href="../../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a> ，然后根据这个对象列表使用合适的模板生成 <a class="reference internal" href="../../ref/template-response.html#django.template.response.TemplateResponse" title="django.template.response.TemplateResponse"><code class="xref py py-class docutils literal notranslate"><span class="pre">TemplateResponse</span></code></a> 。</p>
<p>为了得到对象，<a class="reference internal" href="../../ref/class-based-views/generic-display.html#django.views.generic.list.ListView" title="django.views.generic.list.ListView"><code class="xref py py-class docutils literal notranslate"><span class="pre">ListView</span></code></a> 使用了 <a class="reference internal" href="../../ref/class-based-views/mixins-multiple-object.html#django.views.generic.list.MultipleObjectMixin" title="django.views.generic.list.MultipleObjectMixin"><code class="xref py py-class docutils literal notranslate"><span class="pre">MultipleObjectMixin</span></code></a> ，它同时提供 <a class="reference internal" href="../../ref/class-based-views/mixins-multiple-object.html#django.views.generic.list.MultipleObjectMixin.get_queryset" title="django.views.generic.list.MultipleObjectMixin.get_queryset"><code class="xref py py-meth docutils literal notranslate"><span class="pre">get_queryset()</span></code></a> 和 <a class="reference internal" href="../../ref/class-based-views/mixins-multiple-object.html#django.views.generic.list.MultipleObjectMixin.paginate_queryset" title="django.views.generic.list.MultipleObjectMixin.paginate_queryset"><code class="xref py py-meth docutils literal notranslate"><span class="pre">paginate_queryset()</span></code></a> 。与 <a class="reference internal" href="../../ref/class-based-views/mixins-single-object.html#django.views.generic.detail.SingleObjectMixin" title="django.views.generic.detail.SingleObjectMixin"><code class="xref py py-class docutils literal notranslate"><span class="pre">SingleObjectMixin</span></code></a> 不同的是，不需要使用部分 URL 来找出要使用的查询集，所以默认使用视图类上的 <a class="reference internal" href="../../ref/class-based-views/mixins-multiple-object.html#django.views.generic.list.MultipleObjectMixin.queryset" title="django.views.generic.list.MultipleObjectMixin.queryset"><code class="xref py py-attr docutils literal notranslate"><span class="pre">queryset</span></code></a> 或  <a class="reference internal" href="../../ref/class-based-views/mixins-multiple-object.html#django.views.generic.list.MultipleObjectMixin.model" title="django.views.generic.list.MultipleObjectMixin.model"><code class="xref py py-attr docutils literal notranslate"><span class="pre">model</span></code></a> 属性。在这里覆盖 <a class="reference internal" href="../../ref/class-based-views/mixins-multiple-object.html#django.views.generic.list.MultipleObjectMixin.get_queryset" title="django.views.generic.list.MultipleObjectMixin.get_queryset"><code class="xref py py-meth docutils literal notranslate"><span class="pre">get_queryset()</span></code></a> 的常见原因是为了动态变化的对象，比如根据当前用户的情况，或者为了排除博客未来的文章。</p>
<p><a class="reference internal" href="../../ref/class-based-views/mixins-multiple-object.html#django.views.generic.list.MultipleObjectMixin" title="django.views.generic.list.MultipleObjectMixin"><code class="xref py py-class docutils literal notranslate"><span class="pre">MultipleObjectMixin</span></code></a> 还覆盖了 <a class="reference internal" href="../../ref/class-based-views/mixins-simple.html#django.views.generic.base.ContextMixin.get_context_data" title="django.views.generic.base.ContextMixin.get_context_data"><code class="xref py py-meth docutils literal notranslate"><span class="pre">get_context_data()</span></code></a>，为分页加入了适当的上下文变量（如果分页被禁用，则提供虚假分页）。它依赖于 <a class="reference internal" href="../../ref/class-based-views/flattened-index.html#ListView" title="ListView"><code class="xref py py-class docutils literal notranslate"><span class="pre">ListView</span></code></a> 作为关键字参数传入的 <code class="docutils literal notranslate"><span class="pre">object_list</span></code>。</p>
<p>要生成一个 <a class="reference internal" href="../../ref/template-response.html#django.template.response.TemplateResponse" title="django.template.response.TemplateResponse"><code class="xref py py-class docutils literal notranslate"><span class="pre">TemplateResponse</span></code></a> ，<a class="reference internal" href="../../ref/class-based-views/flattened-index.html#ListView" title="ListView"><code class="xref py py-class docutils literal notranslate"><span class="pre">ListView</span></code></a> 则使用 <a class="reference internal" href="../../ref/class-based-views/mixins-multiple-object.html#django.views.generic.list.MultipleObjectTemplateResponseMixin" title="django.views.generic.list.MultipleObjectTemplateResponseMixin"><code class="xref py py-class docutils literal notranslate"><span class="pre">MultipleObjectTemplateResponseMixin</span></code></a> ；和上面的 <a class="reference internal" href="../../ref/class-based-views/mixins-single-object.html#django.views.generic.detail.SingleObjectTemplateResponseMixin" title="django.views.generic.detail.SingleObjectTemplateResponseMixin"><code class="xref py py-class docutils literal notranslate"><span class="pre">SingleObjectTemplateResponseMixin</span></code></a> 一样，它覆盖 <code class="docutils literal notranslate"><span class="pre">get_template_names()</span></code> 来提供一系列选项，最常用的 <code class="docutils literal notranslate"><span class="pre">&lt;app_label&gt;/&lt;model_name&gt;_list.html</span></code> ，<code class="docutils literal notranslate"><span class="pre">_list</span></code> 部分同样从 <a class="reference internal" href="../../ref/class-based-views/mixins-multiple-object.html#django.views.generic.list.MultipleObjectTemplateResponseMixin.template_name_suffix" title="django.views.generic.list.MultipleObjectTemplateResponseMixin.template_name_suffix"><code class="xref py py-attr docutils literal notranslate"><span class="pre">template_name_suffix</span></code></a> 属性中获取。（基于日期的通用视图使用诸如  <code class="docutils literal notranslate"><span class="pre">_archive</span></code> 、<code class="docutils literal notranslate"><span class="pre">_archive_year</span></code> 等后缀来为各种专门的基于日期的列表视图使用不同的模板。）</p>
</div>
</div>
<div class="section" id="s-using-django-s-class-based-view-mixins">
<span id="using-django-s-class-based-view-mixins"></span><h2>使用 Django 的基于类的视图混入<a class="headerlink" href="#using-django-s-class-based-view-mixins" title="永久链接至标题">¶</a></h2>
<p>现在我们已经知道 Django 的基于类的通用视图如何使用所提供的混入，让我们看看使用它们的其他方式。我们仍然会将它们与内置的基于类的视图，或者其他通用的基于类的视图结合起来，但是，有一系列比 Django 开箱即用所提供的更罕见的问题可以被解决。</p>
<div class="admonition warning">
<p class="first admonition-title">警告</p>
<p>不是所有的混入都可以一起使用，并且不是所有的基于类的通用视图能和所有其他的混入一起使用。这里我们介绍一些有用的例子；如果你想把其他功能汇集在一起，那么你就必须考虑你正在使用的不同类之间重叠的属性和方法之间的相互作用，以及 <a class="reference external" href="https://www.python.org/download/releases/2.3/mro/">method resolution order</a> 将如何影响哪些版本的方法将以何种顺序被调用。</p>
<p>Django 的  <a class="reference internal" href="../../ref/class-based-views/index.html"><span class="doc">基于类的视图</span></a> 和 <a class="reference internal" href="../../ref/class-based-views/mixins.html"><span class="doc">基于类的视图混入</span></a> 的参考文档将帮助你理解哪些属性和方法可能会导致不同类和混入之间发生冲突。</p>
<p class="last">如果有问题，最好还是退而求其次，以 <a class="reference internal" href="../../ref/class-based-views/flattened-index.html#View" title="View"><code class="xref py py-class docutils literal notranslate"><span class="pre">View</span></code></a> 或 <a class="reference internal" href="../../ref/class-based-views/flattened-index.html#TemplateView" title="TemplateView"><code class="xref py py-class docutils literal notranslate"><span class="pre">TemplateView</span></code></a> 为基础，或许可以用 <a class="reference internal" href="../../ref/class-based-views/mixins-single-object.html#django.views.generic.detail.SingleObjectMixin" title="django.views.generic.detail.SingleObjectMixin"><code class="xref py py-class docutils literal notranslate"><span class="pre">SingleObjectMixin</span></code></a> 和 <a class="reference internal" href="../../ref/class-based-views/mixins-multiple-object.html#django.views.generic.list.MultipleObjectMixin" title="django.views.generic.list.MultipleObjectMixin"><code class="xref py py-class docutils literal notranslate"><span class="pre">MultipleObjectMixin</span></code></a> 。虽然你最终可能会写出更多的代码，但对于以后再来的人来说，更有可能清楚地理解，并且由于需要担心的交互较少，你可以省去一些思考。（当然，你可以随时查阅 Django 的基于类的通用视图的实现，以获得如何处理问题的灵感）。</p>
</div>
<div class="section" id="s-using-singleobjectmixin-with-view">
<span id="using-singleobjectmixin-with-view"></span><h3>在视图中使用 <code class="docutils literal notranslate"><span class="pre">SingleObjectMixin</span></code><a class="headerlink" href="#using-singleobjectmixin-with-view" title="永久链接至标题">¶</a></h3>
<p>如果我们想编写一个只响应 <code class="docutils literal notranslate"><span class="pre">POST</span></code> 的基于类的视图，我们将子类化 <a class="reference internal" href="../../ref/class-based-views/base.html#django.views.generic.base.View" title="django.views.generic.base.View"><code class="xref py py-class docutils literal notranslate"><span class="pre">View</span></code></a> 并且在子类中编写一个 <code class="docutils literal notranslate"><span class="pre">post()</span></code> 方法。但是如果想让我们的程序在一个从 URL 中识别出来特定的对象上工作，我们就需要 <a class="reference internal" href="../../ref/class-based-views/mixins-single-object.html#django.views.generic.detail.SingleObjectMixin" title="django.views.generic.detail.SingleObjectMixin"><code class="xref py py-class docutils literal notranslate"><span class="pre">SingleObjectMixin</span></code></a> 提供的功能。</p>
<p>我们将用在 :doc: <cite>基于类的通用视图介绍 &lt;generic-display&gt;</cite> 中使用的 <code class="docutils literal notranslate"><span class="pre">Author</span></code> 模型来演示。</p>
<div class="literal-block-wrapper docutils container" id="id1">
<div class="code-block-caption"><span class="caption-text">views.py</span><a class="headerlink" href="#id1" title="永久链接至代码">¶</a></div>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.http</span> <span class="kn">import</span> <span class="n">HttpResponseForbidden</span><span class="p">,</span> <span class="n">HttpResponseRedirect</span>
<span class="kn">from</span> <span class="nn">django.urls</span> <span class="kn">import</span> <span class="n">reverse</span>
<span class="kn">from</span> <span class="nn">django.views</span> <span class="kn">import</span> <span class="n">View</span>
<span class="kn">from</span> <span class="nn">django.views.generic.detail</span> <span class="kn">import</span> <span class="n">SingleObjectMixin</span>
<span class="kn">from</span> <span class="nn">books.models</span> <span class="kn">import</span> <span class="n">Author</span>

<span class="k">class</span> <span class="nc">RecordInterestView</span><span class="p">(</span><span class="n">SingleObjectMixin</span><span class="p">,</span> <span class="n">View</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;Records the current user&#39;s interest in an author.&quot;&quot;&quot;</span>
    <span class="n">model</span> <span class="o">=</span> <span class="n">Author</span>

    <span class="k">def</span> <span class="nf">post</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">request</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="n">request</span><span class="o">.</span><span class="n">user</span><span class="o">.</span><span class="n">is_authenticated</span><span class="p">:</span>
            <span class="k">return</span> <span class="n">HttpResponseForbidden</span><span class="p">()</span>

        <span class="c1"># Look up the author we&#39;re interested in.</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">object</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_object</span><span class="p">()</span>
        <span class="c1"># Actually record interest somehow here!</span>

        <span class="k">return</span> <span class="n">HttpResponseRedirect</span><span class="p">(</span><span class="n">reverse</span><span class="p">(</span><span class="s1">&#39;author-detail&#39;</span><span class="p">,</span> <span class="n">kwargs</span><span class="o">=</span><span class="p">{</span><span class="s1">&#39;pk&#39;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">object</span><span class="o">.</span><span class="n">pk</span><span class="p">}))</span>
</pre></div>
</div>
</div>
<p>在实际操作中，你可能会希望把兴趣记录在一个键值存储中，而不是关系数据库中，所以我们把关于数据库的省略了。视图在使用 <a class="reference internal" href="../../ref/class-based-views/mixins-single-object.html#django.views.generic.detail.SingleObjectMixin" title="django.views.generic.detail.SingleObjectMixin"><code class="xref py py-class docutils literal notranslate"><span class="pre">SingleObjectMixin</span></code></a> 时，我们唯一需要担心的地方是想要查找我们感兴趣的作者，它通过调用 <code class="docutils literal notranslate"><span class="pre">self.get_object()</span></code> 来实现。其他的一切都由混入替我们处理。</p>
<p>我们可以很简单的将它挂接在我们的 URLs 中：</p>
<div class="literal-block-wrapper docutils container" id="id2">
<div class="code-block-caption"><span class="caption-text">urls.py</span><a class="headerlink" href="#id2" title="永久链接至代码">¶</a></div>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.urls</span> <span class="kn">import</span> <span class="n">path</span>
<span class="kn">from</span> <span class="nn">books.views</span> <span class="kn">import</span> <span class="n">RecordInterestView</span>

<span class="n">urlpatterns</span> <span class="o">=</span> <span class="p">[</span>
    <span class="c1">#...</span>
    <span class="n">path</span><span class="p">(</span><span class="s1">&#39;author/&lt;int:pk&gt;/interest/&#39;</span><span class="p">,</span> <span class="n">RecordInterestView</span><span class="o">.</span><span class="n">as_view</span><span class="p">(),</span> <span class="n">name</span><span class="o">=</span><span class="s1">&#39;author-interest&#39;</span><span class="p">),</span>
<span class="p">]</span>
</pre></div>
</div>
</div>
<p>注意 <code class="docutils literal notranslate"><span class="pre">pk</span></code> 命名的组，<a class="reference internal" href="../../ref/class-based-views/mixins-single-object.html#django.views.generic.detail.SingleObjectMixin.get_object" title="django.views.generic.detail.SingleObjectMixin.get_object"><code class="xref py py-meth docutils literal notranslate"><span class="pre">get_object()</span></code></a> 用它来查找 <code class="docutils literal notranslate"><span class="pre">Author</span></code> 实例。你也可以使用 slug，或者 <a class="reference internal" href="../../ref/class-based-views/mixins-single-object.html#django.views.generic.detail.SingleObjectMixin" title="django.views.generic.detail.SingleObjectMixin"><code class="xref py py-class docutils literal notranslate"><span class="pre">SingleObjectMixin</span></code></a> 的任何其他功能。</p>
</div>
<div class="section" id="s-using-singleobjectmixin-with-listview">
<span id="using-singleobjectmixin-with-listview"></span><h3>在 <code class="docutils literal notranslate"><span class="pre">ListView</span></code> 中使用 <code class="docutils literal notranslate"><span class="pre">SingleObjectMixin</span></code><a class="headerlink" href="#using-singleobjectmixin-with-listview" title="永久链接至标题">¶</a></h3>
<p><a class="reference internal" href="../../ref/class-based-views/generic-display.html#django.views.generic.list.ListView" title="django.views.generic.list.ListView"><code class="xref py py-class docutils literal notranslate"><span class="pre">ListView</span></code></a> 提供了内置的分页功能，但你可能想将一个对象列表分页，而这些对象都是通过一个外键链接到另一个对象的。在我们的出版示例中，你可能想对某一出版商的所有书籍进行分页。</p>
<p>一种方法是将 <a class="reference internal" href="../../ref/class-based-views/flattened-index.html#ListView" title="ListView"><code class="xref py py-class docutils literal notranslate"><span class="pre">ListView</span></code></a> 和 <a class="reference internal" href="../../ref/class-based-views/mixins-single-object.html#django.views.generic.detail.SingleObjectMixin" title="django.views.generic.detail.SingleObjectMixin"><code class="xref py py-class docutils literal notranslate"><span class="pre">SingleObjectMixin</span></code></a> 结合起来，这样一来，用于图书分页列表的查询集就可以脱离作为单个对象找到的出版商对象。 为此，我们需要两个不同的查询集：</p>
<dl class="docutils">
<dt><a class="reference internal" href="../../ref/class-based-views/generic-display.html#django.views.generic.list.ListView" title="django.views.generic.list.ListView"><code class="xref py py-class docutils literal notranslate"><span class="pre">ListView</span></code></a> 使用的 <code class="docutils literal notranslate"><span class="pre">Book</span></code> 查询集</dt>
<dd>由于我们已经得到了我们所想要书籍列表的 <code class="docutils literal notranslate"><span class="pre">Publisher</span></code> ，我们只需覆盖 <code class="docutils literal notranslate"><span class="pre">get_queryset()</span></code> 并使用的 <code class="docutils literal notranslate"><span class="pre">Publisher</span></code> 的 <a class="reference internal" href="../db/queries.html#backwards-related-objects"><span class="std std-ref">反向外键管理器</span></a>。</dd>
<dt><a class="reference internal" href="../../ref/class-based-views/mixins-single-object.html#django.views.generic.detail.SingleObjectMixin.get_object" title="django.views.generic.detail.SingleObjectMixin.get_object"><code class="xref py py-meth docutils literal notranslate"><span class="pre">get_object()</span></code></a> 使用的 <code class="docutils literal notranslate"><span class="pre">Publisher</span></code> 查询集</dt>
<dd>我们将依赖 <code class="docutils literal notranslate"><span class="pre">get_object()</span></code> 的默认实现来获取正确的 <code class="docutils literal notranslate"><span class="pre">Publisher</span></code> 对象。然而，我们需要显式地传递一个 <code class="docutils literal notranslate"><span class="pre">queryset</span></code> 参数，因为 <code class="docutils literal notranslate"><span class="pre">get_object()</span></code> 的默认实现会调用 <code class="docutils literal notranslate"><span class="pre">get_queryset()</span></code> ，我们已经覆盖了它并返回了 <code class="docutils literal notranslate"><span class="pre">Book</span></code> 对象而不是 <code class="docutils literal notranslate"><span class="pre">Publisher</span></code> 对象。</dd>
</dl>
<div class="admonition note">
<p class="first admonition-title">注解</p>
<p class="last">我们必须认真考虑 <code class="docutils literal notranslate"><span class="pre">get_context_data()</span></code>。由于 <a class="reference internal" href="../../ref/class-based-views/mixins-single-object.html#django.views.generic.detail.SingleObjectMixin" title="django.views.generic.detail.SingleObjectMixin"><code class="xref py py-class docutils literal notranslate"><span class="pre">SingleObjectMixin</span></code></a> 和  <a class="reference internal" href="../../ref/class-based-views/flattened-index.html#ListView" title="ListView"><code class="xref py py-class docutils literal notranslate"><span class="pre">ListView</span></code></a> 会将上下文数据放在 <code class="docutils literal notranslate"><span class="pre">context_object_name</span></code> 的值下（如果它已设置），我们要明确确保 <code class="docutils literal notranslate"><span class="pre">Publisher</span></code> 在上下文数据中。<a class="reference internal" href="../../ref/class-based-views/flattened-index.html#ListView" title="ListView"><code class="xref py py-class docutils literal notranslate"><span class="pre">ListView</span></code></a> 将为我们添加合适的 <code class="docutils literal notranslate"><span class="pre">page_obj</span></code> 和 <code class="docutils literal notranslate"><span class="pre">paginator</span></code>，只要我们记得调用 <code class="docutils literal notranslate"><span class="pre">super()</span></code>。</p>
</div>
<p>Now we can write a new <code class="docutils literal notranslate"><span class="pre">PublisherDetailView</span></code>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.views.generic</span> <span class="kn">import</span> <span class="n">ListView</span>
<span class="kn">from</span> <span class="nn">django.views.generic.detail</span> <span class="kn">import</span> <span class="n">SingleObjectMixin</span>
<span class="kn">from</span> <span class="nn">books.models</span> <span class="kn">import</span> <span class="n">Publisher</span>

<span class="k">class</span> <span class="nc">PublisherDetailView</span><span class="p">(</span><span class="n">SingleObjectMixin</span><span class="p">,</span> <span class="n">ListView</span><span class="p">):</span>
    <span class="n">paginate_by</span> <span class="o">=</span> <span class="mi">2</span>
    <span class="n">template_name</span> <span class="o">=</span> <span class="s2">&quot;books/publisher_detail.html&quot;</span>

    <span class="k">def</span> <span class="nf">get</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">request</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">object</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_object</span><span class="p">(</span><span class="n">queryset</span><span class="o">=</span><span class="n">Publisher</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">())</span>
        <span class="k">return</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">get_context_data</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
        <span class="n">context</span> <span class="o">=</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">get_context_data</span><span class="p">(</span><span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
        <span class="n">context</span><span class="p">[</span><span class="s1">&#39;publisher&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">object</span>
        <span class="k">return</span> <span class="n">context</span>

    <span class="k">def</span> <span class="nf">get_queryset</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">object</span><span class="o">.</span><span class="n">book_set</span><span class="o">.</span><span class="n">all</span><span class="p">()</span>
</pre></div>
</div>
<p>注意看我们如何在 <code class="docutils literal notranslate"><span class="pre">get()</span></code> 中设置 <code class="docutils literal notranslate"><span class="pre">self.object</span></code> ，这样我们可以在后面的 <code class="docutils literal notranslate"><span class="pre">get_context_data()</span></code> 和  <code class="docutils literal notranslate"><span class="pre">get_queryset()</span></code> 中再次使用它。如果你没有设置 <code class="docutils literal notranslate"><span class="pre">template_name</span></code> ，模板将为正常 <a class="reference internal" href="../../ref/class-based-views/flattened-index.html#ListView" title="ListView"><code class="xref py py-class docutils literal notranslate"><span class="pre">ListView</span></code></a> 的默认选项，在这个例子里是 <code class="docutils literal notranslate"><span class="pre">&quot;books/book_list.html&quot;</span></code> ，因为它是书籍的列表；<a class="reference internal" href="../../ref/class-based-views/flattened-index.html#ListView" title="ListView"><code class="xref py py-class docutils literal notranslate"><span class="pre">ListView</span></code></a> 对 <a class="reference internal" href="../../ref/class-based-views/mixins-single-object.html#django.views.generic.detail.SingleObjectMixin" title="django.views.generic.detail.SingleObjectMixin"><code class="xref py py-class docutils literal notranslate"><span class="pre">SingleObjectMixin</span></code></a> 一无所知，因此这个视图和 <code class="docutils literal notranslate"><span class="pre">Publisher</span></code> 没有任何关系。</p>
<p>在这个例子中，<code class="docutils literal notranslate"><span class="pre">paginate_by</span></code> 被刻意地缩小了，所以你不需要创建很多书就能看到分页的效果。这里是你要使用的模板：</p>
<div class="highlight-html+django notranslate"><div class="highlight"><pre><span></span><span class="cp">{%</span> <span class="k">extends</span> <span class="s2">&quot;base.html&quot;</span> <span class="cp">%}</span>

<span class="cp">{%</span> <span class="k">block</span> <span class="nv">content</span> <span class="cp">%}</span>
    <span class="p">&lt;</span><span class="nt">h2</span><span class="p">&gt;</span>Publisher <span class="cp">{{</span> <span class="nv">publisher.name</span> <span class="cp">}}</span><span class="p">&lt;/</span><span class="nt">h2</span><span class="p">&gt;</span>

    <span class="p">&lt;</span><span class="nt">ol</span><span class="p">&gt;</span>
      <span class="cp">{%</span> <span class="k">for</span> <span class="nv">book</span> <span class="k">in</span> <span class="nv">page_obj</span> <span class="cp">%}</span>
        <span class="p">&lt;</span><span class="nt">li</span><span class="p">&gt;</span><span class="cp">{{</span> <span class="nv">book.title</span> <span class="cp">}}</span><span class="p">&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
      <span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span>
    <span class="p">&lt;/</span><span class="nt">ol</span><span class="p">&gt;</span>

    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;pagination&quot;</span><span class="p">&gt;</span>
        <span class="p">&lt;</span><span class="nt">span</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;step-links&quot;</span><span class="p">&gt;</span>
            <span class="cp">{%</span> <span class="k">if</span> <span class="nv">page_obj.has_previous</span> <span class="cp">%}</span>
                <span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&quot;?page=</span><span class="cp">{{</span> <span class="nv">page_obj.previous_page_number</span> <span class="cp">}}</span><span class="s">&quot;</span><span class="p">&gt;</span>previous<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
            <span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span>

            <span class="p">&lt;</span><span class="nt">span</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;current&quot;</span><span class="p">&gt;</span>
                Page <span class="cp">{{</span> <span class="nv">page_obj.number</span> <span class="cp">}}</span> of <span class="cp">{{</span> <span class="nv">paginator.num_pages</span> <span class="cp">}}</span>.
            <span class="p">&lt;/</span><span class="nt">span</span><span class="p">&gt;</span>

            <span class="cp">{%</span> <span class="k">if</span> <span class="nv">page_obj.has_next</span> <span class="cp">%}</span>
                <span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&quot;?page=</span><span class="cp">{{</span> <span class="nv">page_obj.next_page_number</span> <span class="cp">}}</span><span class="s">&quot;</span><span class="p">&gt;</span>next<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
            <span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span>
        <span class="p">&lt;/</span><span class="nt">span</span><span class="p">&gt;</span>
    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
<span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span>
</pre></div>
</div>
</div>
</div>
<div class="section" id="s-avoid-anything-more-complex">
<span id="avoid-anything-more-complex"></span><h2>避免过度复杂的事情<a class="headerlink" href="#avoid-anything-more-complex" title="永久链接至标题">¶</a></h2>
<p>一般来说，你可以在需要的时候使用 <a class="reference internal" href="../../ref/class-based-views/mixins-simple.html#django.views.generic.base.TemplateResponseMixin" title="django.views.generic.base.TemplateResponseMixin"><code class="xref py py-class docutils literal notranslate"><span class="pre">TemplateResponseMixin</span></code></a> 和  <a class="reference internal" href="../../ref/class-based-views/mixins-single-object.html#django.views.generic.detail.SingleObjectMixin" title="django.views.generic.detail.SingleObjectMixin"><code class="xref py py-class docutils literal notranslate"><span class="pre">SingleObjectMixin</span></code></a> 的功能。如上所示，只要稍加注意，你甚至可以将 <code class="docutils literal notranslate"><span class="pre">SingleObjectMixin</span></code> 和 <a class="reference internal" href="../../ref/class-based-views/generic-display.html#django.views.generic.list.ListView" title="django.views.generic.list.ListView"><code class="xref py py-class docutils literal notranslate"><span class="pre">ListView</span></code></a> 结合起来。然而当你尝试这样做时，事情会变得越来越复杂，一个好的经验法则是：</p>
<div class="admonition hint">
<p class="first admonition-title">提示</p>
<p class="last">你的每个视图应该只使用混入或者来自一个通用基于类的视图的组里视图： <a class="reference internal" href="generic-display.html"><span class="doc">详情，列表</span></a>，<a class="reference internal" href="generic-editing.html"><span class="doc">编辑</span></a> 和日期。例如，将 <a class="reference internal" href="../../ref/class-based-views/flattened-index.html#TemplateView" title="TemplateView"><code class="xref py py-class docutils literal notranslate"><span class="pre">TemplateView</span></code></a> （内置视图）和 <a class="reference internal" href="../../ref/class-based-views/mixins-multiple-object.html#django.views.generic.list.MultipleObjectMixin" title="django.views.generic.list.MultipleObjectMixin"><code class="xref py py-class docutils literal notranslate"><span class="pre">MultipleObjectMixin</span></code></a> （通用列表）结合起来，但你可能会在 <code class="docutils literal notranslate"><span class="pre">SingleObjectMixin</span></code> （通用详情）和 <code class="docutils literal notranslate"><span class="pre">MultipleObjectMixin</span></code> （通用列表）结合时遇到问题。</p>
</div>
<p>为了给你展示当变得更复杂时发生了什么，我们展示了一个当有更简单的解决方案时，牺牲了可读写和可维护性的例子。首先，让我们看看一个天真的尝试，将 <a class="reference internal" href="../../ref/class-based-views/generic-display.html#django.views.generic.detail.DetailView" title="django.views.generic.detail.DetailView"><code class="xref py py-class docutils literal notranslate"><span class="pre">DetailView</span></code></a> 和 <a class="reference internal" href="../../ref/class-based-views/mixins-editing.html#django.views.generic.edit.FormMixin" title="django.views.generic.edit.FormMixin"><code class="xref py py-class docutils literal notranslate"><span class="pre">FormMixin</span></code></a> 结合起来，使我们能够在 <code class="docutils literal notranslate"><span class="pre">POST</span></code> 一个 Django <a class="reference internal" href="../../ref/forms/api.html#django.forms.Form" title="django.forms.Form"><code class="xref py py-class docutils literal notranslate"><span class="pre">Form</span></code></a> 和显示一个 <a class="reference internal" href="../../ref/class-based-views/flattened-index.html#DetailView" title="DetailView"><code class="xref py py-class docutils literal notranslate"><span class="pre">DetailView</span></code></a> 时使用同一个 URL。</p>
<div class="section" id="s-using-formmixin-with-detailview">
<span id="using-formmixin-with-detailview"></span><h3><code class="docutils literal notranslate"><span class="pre">DetailView</span></code> 和 <code class="docutils literal notranslate"><span class="pre">FormMixin</span></code> 一起使用<a class="headerlink" href="#using-formmixin-with-detailview" title="永久链接至标题">¶</a></h3>
<p>回想一下我们之前使用 <a class="reference internal" href="../../ref/class-based-views/flattened-index.html#View" title="View"><code class="xref py py-class docutils literal notranslate"><span class="pre">View</span></code></a> 和 <a class="reference internal" href="../../ref/class-based-views/mixins-single-object.html#django.views.generic.detail.SingleObjectMixin" title="django.views.generic.detail.SingleObjectMixin"><code class="xref py py-class docutils literal notranslate"><span class="pre">SingleObjectMixin</span></code></a> 一起使用的例子。我们当时记录的是一个用户对某个作者的兴趣；比如说现在我们想让他们留言说为什么喜欢他们。同样，我们假设我们不打算把这个存储在关系型数据库中，而是存储在更深奥的东西中，我们在这里就不关心了。</p>
<p>这时自然而然就会用到一个 <a class="reference internal" href="../../ref/forms/api.html#django.forms.Form" title="django.forms.Form"><code class="xref py py-class docutils literal notranslate"><span class="pre">Form</span></code></a> 来封装从用户浏览器发送到 Django 的信息。又比如说我们在 <a class="reference external" href="https://en.wikipedia.org/wiki/Representational_state_transfer">REST</a> 上投入了大量的精力，所以我们希望用同样的 URL 来显示作者和捕捉用户的信息。让我们重写我们的 <code class="docutils literal notranslate"><span class="pre">AuthorDetailView</span></code> 来实现这个目标。</p>
<p>我们将保留 <a class="reference internal" href="../../ref/class-based-views/flattened-index.html#DetailView" title="DetailView"><code class="xref py py-class docutils literal notranslate"><span class="pre">DetailView</span></code></a> 中的 <code class="docutils literal notranslate"><span class="pre">GET</span></code> 处理，尽管我们必须在上下文数据中添加一个 <a class="reference internal" href="../../ref/forms/api.html#django.forms.Form" title="django.forms.Form"><code class="xref py py-class docutils literal notranslate"><span class="pre">Form</span></code></a>，这样我们就可以在模板中渲染它。我们还要从 <a class="reference internal" href="../../ref/class-based-views/mixins-editing.html#django.views.generic.edit.FormMixin" title="django.views.generic.edit.FormMixin"><code class="xref py py-class docutils literal notranslate"><span class="pre">FormMixin</span></code></a> 中调入表单处理，并写一点代码，这样在 <a href="#id1"><span class="problematic" id="id2">``</span></a>POST` <a href="#id3"><span class="problematic" id="id4">`</span></a>时，表单会被适当地调用。</p>
<div class="admonition note">
<p class="first admonition-title">注解</p>
<p class="last">我们使用 <a class="reference internal" href="../../ref/class-based-views/mixins-editing.html#django.views.generic.edit.FormMixin" title="django.views.generic.edit.FormMixin"><code class="xref py py-class docutils literal notranslate"><span class="pre">FormMixin</span></code></a> 并自己实现了 <code class="docutils literal notranslate"><span class="pre">post()</span></code> ，而不是试着把 <a class="reference internal" href="../../ref/class-based-views/flattened-index.html#DetailView" title="DetailView"><code class="xref py py-class docutils literal notranslate"><span class="pre">DetailView</span></code></a> 和 <a class="reference internal" href="../../ref/class-based-views/flattened-index.html#FormView" title="FormView"><code class="xref py py-class docutils literal notranslate"><span class="pre">FormView</span></code></a> （也都提供合适的 <code class="docutils literal notranslate"><span class="pre">post()</span></code>）混着用，因为这两个视图都实现了 <code class="docutils literal notranslate"><span class="pre">get()</span></code> ，这样会让事情变得更复杂。</p>
</div>
<p>Our new <code class="docutils literal notranslate"><span class="pre">AuthorDetailView</span></code> looks like this:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># CAUTION: you almost certainly do not want to do this.</span>
<span class="c1"># It is provided as part of a discussion of problems you can</span>
<span class="c1"># run into when combining different generic class-based view</span>
<span class="c1"># functionality that is not designed to be used together.</span>

<span class="kn">from</span> <span class="nn">django</span> <span class="kn">import</span> <span class="n">forms</span>
<span class="kn">from</span> <span class="nn">django.http</span> <span class="kn">import</span> <span class="n">HttpResponseForbidden</span>
<span class="kn">from</span> <span class="nn">django.urls</span> <span class="kn">import</span> <span class="n">reverse</span>
<span class="kn">from</span> <span class="nn">django.views.generic</span> <span class="kn">import</span> <span class="n">DetailView</span>
<span class="kn">from</span> <span class="nn">django.views.generic.edit</span> <span class="kn">import</span> <span class="n">FormMixin</span>
<span class="kn">from</span> <span class="nn">books.models</span> <span class="kn">import</span> <span class="n">Author</span>

<span class="k">class</span> <span class="nc">AuthorInterestForm</span><span class="p">(</span><span class="n">forms</span><span class="o">.</span><span class="n">Form</span><span class="p">):</span>
    <span class="n">message</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">CharField</span><span class="p">()</span>

<span class="k">class</span> <span class="nc">AuthorDetailView</span><span class="p">(</span><span class="n">FormMixin</span><span class="p">,</span> <span class="n">DetailView</span><span class="p">):</span>
    <span class="n">model</span> <span class="o">=</span> <span class="n">Author</span>
    <span class="n">form_class</span> <span class="o">=</span> <span class="n">AuthorInterestForm</span>

    <span class="k">def</span> <span class="nf">get_success_url</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="n">reverse</span><span class="p">(</span><span class="s1">&#39;author-detail&#39;</span><span class="p">,</span> <span class="n">kwargs</span><span class="o">=</span><span class="p">{</span><span class="s1">&#39;pk&#39;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">object</span><span class="o">.</span><span class="n">pk</span><span class="p">})</span>

    <span class="k">def</span> <span class="nf">post</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">request</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="n">request</span><span class="o">.</span><span class="n">user</span><span class="o">.</span><span class="n">is_authenticated</span><span class="p">:</span>
            <span class="k">return</span> <span class="n">HttpResponseForbidden</span><span class="p">()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">object</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_object</span><span class="p">()</span>
        <span class="n">form</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_form</span><span class="p">()</span>
        <span class="k">if</span> <span class="n">form</span><span class="o">.</span><span class="n">is_valid</span><span class="p">():</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">form_valid</span><span class="p">(</span><span class="n">form</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">form_invalid</span><span class="p">(</span><span class="n">form</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">form_valid</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">form</span><span class="p">):</span>
        <span class="c1"># Here, we would record the user&#39;s interest using the message</span>
        <span class="c1"># passed in form.cleaned_data[&#39;message&#39;]</span>
        <span class="k">return</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">form_valid</span><span class="p">(</span><span class="n">form</span><span class="p">)</span>
</pre></div>
</div>
<p><code class="docutils literal notranslate"><span class="pre">get_success_url()</span></code> 提供了重定向的去处，它在 <code class="docutils literal notranslate"><span class="pre">form_valid()</span></code> 的默认实现中使用。如前所述，我们需要提供自己的 <code class="docutils literal notranslate"><span class="pre">post()</span></code> 。</p>
</div>
<div class="section" id="s-a-better-solution">
<span id="a-better-solution"></span><h3>更好的解决方案<a class="headerlink" href="#a-better-solution" title="永久链接至标题">¶</a></h3>
<p><a class="reference internal" href="../../ref/class-based-views/mixins-editing.html#django.views.generic.edit.FormMixin" title="django.views.generic.edit.FormMixin"><code class="xref py py-class docutils literal notranslate"><span class="pre">FormMixin</span></code></a> 和 <a class="reference internal" href="../../ref/class-based-views/flattened-index.html#DetailView" title="DetailView"><code class="xref py py-class docutils literal notranslate"><span class="pre">DetailView</span></code></a> 之间微妙交互已经在测试我们管理事务的能力了。你不太可能想写这样的类。</p>
<p>在这个例子里，你可以编写 <code class="docutils literal notranslate"><span class="pre">post()</span></code> 让 <a class="reference internal" href="../../ref/class-based-views/flattened-index.html#DetailView" title="DetailView"><code class="xref py py-class docutils literal notranslate"><span class="pre">DetailView</span></code></a> 作为唯一的通用功能，尽管编写 <a class="reference internal" href="../../ref/forms/api.html#django.forms.Form" title="django.forms.Form"><code class="xref py py-class docutils literal notranslate"><span class="pre">Form</span></code></a> 的处理代码会涉及到很多重复的地方。</p>
<p>或者，使用单独的视图来处理表单仍然比上述方法工作量小，它可以使用 <a class="reference internal" href="../../ref/class-based-views/generic-editing.html#django.views.generic.edit.FormView" title="django.views.generic.edit.FormView"><code class="xref py py-class docutils literal notranslate"><span class="pre">FormView</span></code></a> ，而不必担心任何问题。</p>
</div>
<div class="section" id="s-an-alternative-better-solution">
<span id="an-alternative-better-solution"></span><h3>另一种更好的解决方案<a class="headerlink" href="#an-alternative-better-solution" title="永久链接至标题">¶</a></h3>
<p>我们在这里真正想做的是在同一个 URL 中使用两个不同的基于类的视图。那么为什么不这样做呢？我们在这里有一个非常明确的划分。<code class="docutils literal notranslate"><span class="pre">GET</span></code> 请求应该得到 <a class="reference internal" href="../../ref/class-based-views/flattened-index.html#DetailView" title="DetailView"><code class="xref py py-class docutils literal notranslate"><span class="pre">DetailView</span></code></a> （在上下文数据中添加了 <a class="reference internal" href="../../ref/forms/api.html#django.forms.Form" title="django.forms.Form"><code class="xref py py-class docutils literal notranslate"><span class="pre">Form</span></code></a> ），而 <code class="docutils literal notranslate"><span class="pre">POST</span></code> 请求应该得到 <a class="reference internal" href="../../ref/class-based-views/flattened-index.html#FormView" title="FormView"><code class="xref py py-class docutils literal notranslate"><span class="pre">FormView</span></code></a>。我们先来设置一下这些视图。</p>
<p>The <code class="docutils literal notranslate"><span class="pre">AuthorDetailView</span></code> view is almost the same as <a class="reference internal" href="generic-display.html#generic-views-extra-work"><span class="std std-ref">when we
first introduced AuthorDetailView</span></a>; we have to
write our own <code class="docutils literal notranslate"><span class="pre">get_context_data()</span></code> to make the
<code class="docutils literal notranslate"><span class="pre">AuthorInterestForm</span></code> available to the template. We'll skip the
<code class="docutils literal notranslate"><span class="pre">get_object()</span></code> override from before for clarity:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django</span> <span class="kn">import</span> <span class="n">forms</span>
<span class="kn">from</span> <span class="nn">django.views.generic</span> <span class="kn">import</span> <span class="n">DetailView</span>
<span class="kn">from</span> <span class="nn">books.models</span> <span class="kn">import</span> <span class="n">Author</span>

<span class="k">class</span> <span class="nc">AuthorInterestForm</span><span class="p">(</span><span class="n">forms</span><span class="o">.</span><span class="n">Form</span><span class="p">):</span>
    <span class="n">message</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">CharField</span><span class="p">()</span>

<span class="k">class</span> <span class="nc">AuthorDetailView</span><span class="p">(</span><span class="n">DetailView</span><span class="p">):</span>
    <span class="n">model</span> <span class="o">=</span> <span class="n">Author</span>

    <span class="k">def</span> <span class="nf">get_context_data</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
        <span class="n">context</span> <span class="o">=</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">get_context_data</span><span class="p">(</span><span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
        <span class="n">context</span><span class="p">[</span><span class="s1">&#39;form&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">AuthorInterestForm</span><span class="p">()</span>
        <span class="k">return</span> <span class="n">context</span>
</pre></div>
</div>
<p>Then the <code class="docutils literal notranslate"><span class="pre">AuthorInterestForm</span></code> is a <a class="reference internal" href="../../ref/class-based-views/flattened-index.html#FormView" title="FormView"><code class="xref py py-class docutils literal notranslate"><span class="pre">FormView</span></code></a>, but we have to bring in
<a class="reference internal" href="../../ref/class-based-views/mixins-single-object.html#django.views.generic.detail.SingleObjectMixin" title="django.views.generic.detail.SingleObjectMixin"><code class="xref py py-class docutils literal notranslate"><span class="pre">SingleObjectMixin</span></code></a> so we can find the
author we're talking about, and we have to remember to set <code class="docutils literal notranslate"><span class="pre">template_name</span></code> to
ensure that form errors will render the same template as <code class="docutils literal notranslate"><span class="pre">AuthorDetailView</span></code>
is using on <code class="docutils literal notranslate"><span class="pre">GET</span></code>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.http</span> <span class="kn">import</span> <span class="n">HttpResponseForbidden</span>
<span class="kn">from</span> <span class="nn">django.urls</span> <span class="kn">import</span> <span class="n">reverse</span>
<span class="kn">from</span> <span class="nn">django.views.generic</span> <span class="kn">import</span> <span class="n">FormView</span>
<span class="kn">from</span> <span class="nn">django.views.generic.detail</span> <span class="kn">import</span> <span class="n">SingleObjectMixin</span>

<span class="k">class</span> <span class="nc">AuthorInterestFormView</span><span class="p">(</span><span class="n">SingleObjectMixin</span><span class="p">,</span> <span class="n">FormView</span><span class="p">):</span>
    <span class="n">template_name</span> <span class="o">=</span> <span class="s1">&#39;books/author_detail.html&#39;</span>
    <span class="n">form_class</span> <span class="o">=</span> <span class="n">AuthorInterestForm</span>
    <span class="n">model</span> <span class="o">=</span> <span class="n">Author</span>

    <span class="k">def</span> <span class="nf">post</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">request</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="n">request</span><span class="o">.</span><span class="n">user</span><span class="o">.</span><span class="n">is_authenticated</span><span class="p">:</span>
            <span class="k">return</span> <span class="n">HttpResponseForbidden</span><span class="p">()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">object</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_object</span><span class="p">()</span>
        <span class="k">return</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">get_success_url</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="n">reverse</span><span class="p">(</span><span class="s1">&#39;author-detail&#39;</span><span class="p">,</span> <span class="n">kwargs</span><span class="o">=</span><span class="p">{</span><span class="s1">&#39;pk&#39;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">object</span><span class="o">.</span><span class="n">pk</span><span class="p">})</span>
</pre></div>
</div>
<p>Finally we bring this together in a new <code class="docutils literal notranslate"><span class="pre">AuthorView</span></code> view. We
already know that calling <a class="reference internal" href="../../ref/class-based-views/base.html#django.views.generic.base.View.as_view" title="django.views.generic.base.View.as_view"><code class="xref py py-meth docutils literal notranslate"><span class="pre">as_view()</span></code></a> on
a class-based view gives us something that behaves exactly like a function
based view, so we can do that at the point we choose between the two subviews.</p>
<p>You can pass through keyword arguments to
<a class="reference internal" href="../../ref/class-based-views/base.html#django.views.generic.base.View.as_view" title="django.views.generic.base.View.as_view"><code class="xref py py-meth docutils literal notranslate"><span class="pre">as_view()</span></code></a> in the same way you
would in your URLconf, such as if you wanted the <code class="docutils literal notranslate"><span class="pre">AuthorInterestFormView</span></code>
behavior to also appear at another URL but using a different template:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.views</span> <span class="kn">import</span> <span class="n">View</span>

<span class="k">class</span> <span class="nc">AuthorView</span><span class="p">(</span><span class="n">View</span><span class="p">):</span>

    <span class="k">def</span> <span class="nf">get</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">request</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
        <span class="n">view</span> <span class="o">=</span> <span class="n">AuthorDetailView</span><span class="o">.</span><span class="n">as_view</span><span class="p">()</span>
        <span class="k">return</span> <span class="n">view</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">post</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">request</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
        <span class="n">view</span> <span class="o">=</span> <span class="n">AuthorInterestFormView</span><span class="o">.</span><span class="n">as_view</span><span class="p">()</span>
        <span class="k">return</span> <span class="n">view</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
</pre></div>
</div>
<p>这个方式也可以被任何其他通用基于类的视图，或你自己实现的直接继承自 <a class="reference internal" href="../../ref/class-based-views/flattened-index.html#View" title="View"><code class="xref py py-class docutils literal notranslate"><span class="pre">View</span></code></a> 或 <a class="reference internal" href="../../ref/class-based-views/flattened-index.html#TemplateView" title="TemplateView"><code class="xref py py-class docutils literal notranslate"><span class="pre">TemplateView</span></code></a> 的基于类的视图使用，因为它使不同视图尽可能分离。</p>
</div>
</div>
<div class="section" id="s-more-than-just-html">
<span id="s-jsonresponsemixin-example"></span><span id="more-than-just-html"></span><span id="jsonresponsemixin-example"></span><h2>不仅仅是 HTML<a class="headerlink" href="#more-than-just-html" title="永久链接至标题">¶</a></h2>
<p>基于类的视图的优势是你可以多次执行相同操作。假设你正在编写 API，那么每个视图应该返回 JSON，而不是渲染 HTML。</p>
<p>我们可以创建一个混入类来在所有视图里使用，用它来进行一次转换到 JSON。</p>
<p>比如，一个 JSON 混入可以是这样：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.http</span> <span class="kn">import</span> <span class="n">JsonResponse</span>

<span class="k">class</span> <span class="nc">JSONResponseMixin</span><span class="p">:</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    A mixin that can be used to render a JSON response.</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="k">def</span> <span class="nf">render_to_json_response</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">context</span><span class="p">,</span> <span class="o">**</span><span class="n">response_kwargs</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Returns a JSON response, transforming &#39;context&#39; to make the payload.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="n">JsonResponse</span><span class="p">(</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">get_data</span><span class="p">(</span><span class="n">context</span><span class="p">),</span>
            <span class="o">**</span><span class="n">response_kwargs</span>
        <span class="p">)</span>

    <span class="k">def</span> <span class="nf">get_data</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">context</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Returns an object that will be serialized as JSON by json.dumps().</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="c1"># Note: This is *EXTREMELY* naive; in reality, you&#39;ll need</span>
        <span class="c1"># to do much more complex handling to ensure that arbitrary</span>
        <span class="c1"># objects -- such as Django model instances or querysets</span>
        <span class="c1"># -- can be serialized as JSON.</span>
        <span class="k">return</span> <span class="n">context</span>
</pre></div>
</div>
<div class="admonition note">
<p class="first admonition-title">注解</p>
<p class="last">查看 <a class="reference internal" href="../serialization.html"><span class="doc">序列化 Django 对象</span></a> 文档来获取更多有关如何正确转换 Django 模型和查询集为 JSON。</p>
</div>
<p>混入提供了 <code class="docutils literal notranslate"><span class="pre">render_to_json_response()</span></code> 方法，其签名与 <a class="reference internal" href="../../ref/class-based-views/mixins-simple.html#django.views.generic.base.TemplateResponseMixin.render_to_response" title="django.views.generic.base.TemplateResponseMixin.render_to_response"><code class="xref py py-func docutils literal notranslate"><span class="pre">render_to_response()</span></code></a> 相同。为了使用它，我们需要把它混入一个 <code class="docutils literal notranslate"><span class="pre">TemplateView</span></code> 里，并且重写 <code class="docutils literal notranslate"><span class="pre">render_to_response()</span></code> 来调用 <code class="docutils literal notranslate"><span class="pre">render_to_json_response()</span></code> ：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.views.generic</span> <span class="kn">import</span> <span class="n">TemplateView</span>

<span class="k">class</span> <span class="nc">JSONView</span><span class="p">(</span><span class="n">JSONResponseMixin</span><span class="p">,</span> <span class="n">TemplateView</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">render_to_response</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">context</span><span class="p">,</span> <span class="o">**</span><span class="n">response_kwargs</span><span class="p">):</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">render_to_json_response</span><span class="p">(</span><span class="n">context</span><span class="p">,</span> <span class="o">**</span><span class="n">response_kwargs</span><span class="p">)</span>
</pre></div>
</div>
<p>Equally we could use our mixin with one of the generic views. We can make our
own version of <a class="reference internal" href="../../ref/class-based-views/generic-display.html#django.views.generic.detail.DetailView" title="django.views.generic.detail.DetailView"><code class="xref py py-class docutils literal notranslate"><span class="pre">DetailView</span></code></a> by mixing
<code class="docutils literal notranslate"><span class="pre">JSONResponseMixin</span></code> with the
<a class="reference internal" href="../../ref/class-based-views/generic-display.html#django.views.generic.detail.BaseDetailView" title="django.views.generic.detail.BaseDetailView"><code class="xref py py-class docutils literal notranslate"><span class="pre">BaseDetailView</span></code></a> -- (the
<a class="reference internal" href="../../ref/class-based-views/generic-display.html#django.views.generic.detail.DetailView" title="django.views.generic.detail.DetailView"><code class="xref py py-class docutils literal notranslate"><span class="pre">DetailView</span></code></a> before template
rendering behavior has been mixed in):</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.views.generic.detail</span> <span class="kn">import</span> <span class="n">BaseDetailView</span>

<span class="k">class</span> <span class="nc">JSONDetailView</span><span class="p">(</span><span class="n">JSONResponseMixin</span><span class="p">,</span> <span class="n">BaseDetailView</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">render_to_response</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">context</span><span class="p">,</span> <span class="o">**</span><span class="n">response_kwargs</span><span class="p">):</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">render_to_json_response</span><span class="p">(</span><span class="n">context</span><span class="p">,</span> <span class="o">**</span><span class="n">response_kwargs</span><span class="p">)</span>
</pre></div>
</div>
<p>然后这个视图和其他 <a class="reference internal" href="../../ref/class-based-views/generic-display.html#django.views.generic.detail.DetailView" title="django.views.generic.detail.DetailView"><code class="xref py py-class docutils literal notranslate"><span class="pre">DetailView</span></code></a> 使用相同方式部署，除了响应的格式外其他都相同。</p>
<p>如果你想更激进一些，你甚至可以混合一个 <a class="reference internal" href="../../ref/class-based-views/generic-display.html#django.views.generic.detail.DetailView" title="django.views.generic.detail.DetailView"><code class="xref py py-class docutils literal notranslate"><span class="pre">DetailView</span></code></a> 子类，它可以根据 HTTP 请求的一些属性（比如一个查询参数或 HTTP 请求头），返回 HTML <em>或</em> JSON。只需混合 <code class="docutils literal notranslate"><span class="pre">JSONResponseMixin</span></code> 和 <a class="reference internal" href="../../ref/class-based-views/mixins-single-object.html#django.views.generic.detail.SingleObjectTemplateResponseMixin" title="django.views.generic.detail.SingleObjectTemplateResponseMixin"><code class="xref py py-class docutils literal notranslate"><span class="pre">SingleObjectTemplateResponseMixin</span></code></a> ，并重写  <a class="reference internal" href="../../ref/class-based-views/mixins-simple.html#django.views.generic.base.TemplateResponseMixin.render_to_response" title="django.views.generic.base.TemplateResponseMixin.render_to_response"><code class="xref py py-func docutils literal notranslate"><span class="pre">render_to_response()</span></code></a> 的实现，来根据用户请求的响应类型来返回适当的渲染方法。</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.views.generic.detail</span> <span class="kn">import</span> <span class="n">SingleObjectTemplateResponseMixin</span>

<span class="k">class</span> <span class="nc">HybridDetailView</span><span class="p">(</span><span class="n">JSONResponseMixin</span><span class="p">,</span> <span class="n">SingleObjectTemplateResponseMixin</span><span class="p">,</span> <span class="n">BaseDetailView</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">render_to_response</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">context</span><span class="p">):</span>
        <span class="c1"># Look for a &#39;format=json&#39; GET argument</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">request</span><span class="o">.</span><span class="n">GET</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;format&#39;</span><span class="p">)</span> <span class="o">==</span> <span class="s1">&#39;json&#39;</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">render_to_json_response</span><span class="p">(</span><span class="n">context</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">return</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">render_to_response</span><span class="p">(</span><span class="n">context</span><span class="p">)</span>
</pre></div>
</div>
<p>由于 Python 解析方法重载的方式，对 <code class="docutils literal notranslate"><span class="pre">super().render_to_response(context)</span></code> 的调用最终会调用 <a class="reference internal" href="../../ref/class-based-views/mixins-simple.html#django.views.generic.base.TemplateResponseMixin" title="django.views.generic.base.TemplateResponseMixin"><code class="xref py py-class docutils literal notranslate"><span class="pre">TemplateResponseMixin</span></code></a> 的 <a class="reference internal" href="../../ref/class-based-views/mixins-simple.html#django.views.generic.base.TemplateResponseMixin.render_to_response" title="django.views.generic.base.TemplateResponseMixin.render_to_response"><code class="xref py py-meth docutils literal notranslate"><span class="pre">render_to_response()</span></code></a> 实现。</p>
</div>
</div>


          </div>
        </div>
      </div>
      
        
          <div class="yui-b" id="sidebar">
            
      <div class="sphinxsidebar" role="navigation" aria-label="main navigation">
        <div class="sphinxsidebarwrapper">
  <h3><a href="../../contents.html">Table of Contents</a></h3>
  <ul>
<li><a class="reference internal" href="#">在基于类的视图中使用混入</a><ul>
<li><a class="reference internal" href="#context-and-template-responses">上下文和模板响应</a></li>
<li><a class="reference internal" href="#building-up-django-s-generic-class-based-views">构造 Django 基于类的通用视图</a><ul>
<li><a class="reference internal" href="#detailview-working-with-a-single-django-object"><code class="docutils literal notranslate"><span class="pre">DetailView</span></code> ：使用单个 Django 对象</a></li>
<li><a class="reference internal" href="#listview-working-with-many-django-objects"><code class="docutils literal notranslate"><span class="pre">ListView</span></code> ：使用多个 Django 对象</a></li>
</ul>
</li>
<li><a class="reference internal" href="#using-django-s-class-based-view-mixins">使用 Django 的基于类的视图混入</a><ul>
<li><a class="reference internal" href="#using-singleobjectmixin-with-view">在视图中使用 <code class="docutils literal notranslate"><span class="pre">SingleObjectMixin</span></code></a></li>
<li><a class="reference internal" href="#using-singleobjectmixin-with-listview">在 <code class="docutils literal notranslate"><span class="pre">ListView</span></code> 中使用 <code class="docutils literal notranslate"><span class="pre">SingleObjectMixin</span></code></a></li>
</ul>
</li>
<li><a class="reference internal" href="#avoid-anything-more-complex">避免过度复杂的事情</a><ul>
<li><a class="reference internal" href="#using-formmixin-with-detailview"><code class="docutils literal notranslate"><span class="pre">DetailView</span></code> 和 <code class="docutils literal notranslate"><span class="pre">FormMixin</span></code> 一起使用</a></li>
<li><a class="reference internal" href="#a-better-solution">更好的解决方案</a></li>
<li><a class="reference internal" href="#an-alternative-better-solution">另一种更好的解决方案</a></li>
</ul>
</li>
<li><a class="reference internal" href="#more-than-just-html">不仅仅是 HTML</a></li>
</ul>
</li>
</ul>

  <h4>上一个主题</h4>
  <p class="topless"><a href="generic-editing.html"
                        title="上一章">使用基于类的视图处理表单</a></p>
  <h4>下一个主题</h4>
  <p class="topless"><a href="../migrations.html"
                        title="下一章">迁移</a></p>
  <div role="note" aria-label="source link">
    <h3>本页</h3>
    <ul class="this-page-menu">
      <li><a href="../../_sources/topics/class-based-views/mixins.txt"
            rel="nofollow">显示源代码</a></li>
    </ul>
   </div>
<div id="searchbox" style="display: none" role="search">
  <h3>快速搜索</h3>
    <div class="searchformwrapper">
    <form class="search" action="../../search.html" method="get">
      <input type="text" name="q" />
      <input type="submit" value="转向" />
      <input type="hidden" name="check_keywords" value="yes" />
      <input type="hidden" name="area" value="default" />
    </form>
    </div>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
        </div>
      </div>
              <h3>Last update:</h3>
              <p class="topless">12月 07, 2021</p>
          </div>
        
      
    </div>

    <div id="ft">
      <div class="nav">
    &laquo; <a href="generic-editing.html" title="使用基于类的视图处理表单">previous</a>
     |
    <a href="../index.html" title="使用 Django" accesskey="U">up</a>
   |
    <a href="../migrations.html" title="迁移">next</a> &raquo;</div>
    </div>
  </div>

      <div class="clearer"></div>
    </div>
  </body>
</html>